<?php

class EasyReflector
{
	/**
	 * reflect a class
	 *
	 * @param string $path from JROOT
	 * @param string $file filename
	 */
	function reflect($baseDir, $sub_package, $sub_sub_package, $sub_sub_sub_package, $fileName, $output_format, $raw=false)
	{
		jimport('joomla.filesystem.file');

		$rawObject = new JObject();
		$rawObject->subPackage = $sub_package;
		$rawObject->subSubPackage = $sub_sub_package;
		$rawObject->subSubSubPackage = $sub_sub_sub_package;
		$rawObject->fileName = $fileName;
		$rawObject->classes = array();

		$s =( $sub_sub_package ) ? $sub_sub_package.DS : '';
		$ss =( $sub_sub_sub_package ) ? $sub_sub_sub_package.DS : '';

		$fullPath = $baseDir.DS.$sub_package.DS.$s.$ss.$fileName;

		$html = '';

		$wikiClassPage = '';
		$wikiClassPrefix = 'Joomla!_Programmierung/Framework';
		$wikiMethodsPages = array();

		if($sub_package == 'html')
		{
			if($sub_sub_package == 'parameter' && $sub_sub_sub_package == 'element')
			{
				include_once $baseDir.DS.'html'.DS.'parameter'.DS.'element.php';
			}
			if($sub_sub_package == 'toolbar' && $sub_sub_sub_package == 'button')
			{
				include_once $baseDir.DS.'html'.DS.'toolbar'.DS.'button.php';
			}
		}
		if($sub_package == 'document')
		{
			if($sub_sub_package == 'html' && $sub_sub_sub_package == 'renderer')
			{
				include_once $baseDir.DS.'document'.DS.'renderer.php';
			}
			if($sub_sub_package == 'feed' && $sub_sub_sub_package == 'renderer')
			{
				include_once $baseDir.DS.'document'.DS.'renderer.php';
			}

		}
		if($sub_package == 'template')
		{
			$patPath = JPATH_ROOT.DS.'libraries'.DS.'pattemplate';
			include_once $patPath.DS.'patTemplate'.DS.'Module.php';
			include_once $patPath.DS.'patTemplate'.DS.'Function.php';
			include_once $patPath.DS.'patTemplate'.DS.'Modifier.php';
			if($sub_sub_package == 'html' && $sub_sub_sub_package == 'renderer')
			{
			}
			if($sub_sub_package == 'feed' && $sub_sub_sub_package == 'renderer')
			{
			}

		}

		$allClasses = get_declared_classes();

		/*
		 * WE INCLUDE A FILE !!
		 * TODO whatelse ??
		 */
		include_once $fullPath;
		# @todo jimport...

		$foundClasses = array_diff(get_declared_classes(), $allClasses);

		//--Exeptions from the rules..
		if( ! count($foundClasses))
		{
			if($fileName == 'methods.php')
			{
				$foundClasses = array('JRoute', 'JText');
			}
			if($fileName == 'ini.php')
			{
				$foundClasses = array('JRegistryFormatINI');
			}
			if($fileName == 'Sef.php')
			{
				$foundClasses = array('JRegistryFormatINI');
			}
		}

		if( ! count($foundClasses))
		{
			$testMessage = '';
			//--Check for classes already loaded
			$coreTest = JFile::stripExt(JFile::getName($fullPath));
			$coreTest =( strtolower($coreTest) == 'helper' ) ? 'J'.$sub_package.'Helper' : 'J'.$coreTest;
			$testMessage .= $coreTest.BR;
			if( class_exists($coreTest))
			{
				$foundClasses = array($coreTest);
			}
			else
			{
				$coreTest =  'J'.$sub_package.JFile::stripExt(JFile::getName($fullPath));
				$testMessage .= $coreTest.BR;
				if( class_exists($coreTest))
				{
					$foundClasses = array($coreTest);
				}
				else
				{
					if( $sub_sub_package )
					{
						$coreTest = 'J'.$sub_sub_package.JFile::stripExt(JFile::getName($fullPath));

					}
					if( class_exists($coreTest))
					{
						$foundClasses = array($coreTest);
					}
					else
					{
						return 'No classes found - '.BR.$testMessage;
					}
				}
			}
		}

		foreach ($foundClasses as $clas)
		{
			$theClass = new ReflectionClass($clas);

			$rawObject->classes[] = $theClass;

			$parent = $theClass->getParentClass();
			$parentName =( $parent ) ? ' Extends: <span style="color: orange;">'.$parent->name.'</span>':'';

			$html .= '<h1>';
			$html .= sprintf(
               "%s%s%s %s" ,
			$theClass->isInternal() ? 'internal' : 'user-defined',
			$theClass->isAbstract() ? ' abstract' : '',
			$theClass->isFinal() ? ' final' : '',
			$theClass->isInterface() ? 'Interface' : 'Class'
			);
			#			$html .= '<h1>';
			$html .= ' <span style="color: blue;">'.$theClass->getName().'</span>'.$parentName;
			$html .= '</h1>';
			$html .= '<pre>'.$theClass->getDocComment().'</pre>';
			$html .= NL.'<h2>Properties</h2>';

			$wikiClassPage .= '{{RightTOC}}';
			$wikiClassPage .= "'''".$theClass->getName()."'''".' {{@todo|Beschreibung}}'.NL.NL;
			$wikiClassPage .= '<source lang="php">Der DocComment dient nur zur Referenz - bitte entfernen'.NL.$theClass->getDocComment().NL.'</source>'.NL.NL;

			$comment = explode(NL, $theClass->getDocComment());
			$searches = array('static', 'subpackage', 'since');
			$subPackage = '';
			foreach ($comment as $c)
			{
				foreach ($searches as $search)
				{
					if( strpos($c, '@'.$search))
					{
						#$wikiClassPage .= $c.NL;;
						if( $search == 'subpackage')
						{
							$p =  strpos($c, $search);
							$subPackage = trim(substr($c, strpos($c, $search)+strlen($search)));
						}
					}
				}//foreach
			}//foreach

			$subPackage =( $subPackage ) ? $subPackage : $sub_package;

			$theClass->subPackage = $sub_package;
			$theClass->subPackageName = $subPackage;
			$theClass->subSubPackage = $sub_sub_package;
			$theClass->subSubSubPackage = $sub_sub_sub_package;
			#			$theClass->subPackageName = $subPackage;


			$properties = $theClass->getProperties();
			foreach ($properties as $prop)
			{
				$property = $theClass->getProperty($prop->name);

				$html .= BR.sprintf(
                  "%s%s%s%s property <strong>%s</strong>",
				$property->isPublic() ? ' <strong style="color: green">public</strong>' : '',
				$property->isPrivate() ? ' <strong style="color: orange">private</strong>' : '',
				$property->isProtected() ? ' <strong style="color: red">protected</strong>' : '',
				$property->isStatic() ? ' <strong style="color: black">static</strong>' : '',
				$property->getName()

				);
			}//foreach


			//          $constants = $theClass->getConstants();
			//          print_r($constants);
			// Dokumentarischen Kommentar ausgeben
			//printf("---> Dokumentation:\n %s\n", var_export($theClass->getDocComment(), 1));
			//
			//// Ausgeben, welche Interfaces von der Klasse implementiert werden
			//printf("---> Implementiert:\n %s\n", var_export($theClass->getInterfaces(), 1));
			//
			//// Klassenkonstanten ausgeben
			//printf("---> Konstanten: %s\n", var_export($theClass->getConstants(), 1));
			//
			//// Klasseneigenschaften ausgeben
			//printf("---> Eigenschaften: %s\n", var_export($theClass->getProperties(), 1));
			//
			//// Klassenmethoden ausgeben
			//printf("---> Methoden: %s\n", var_export($theClass->getMethods(), 1));echo '</pre>';
			#echo $theClass->getDocComment();
			//          echo '<pre>';
			//          printf(
			//             "===> %s%s%s %s '%s' [extends %s]\n" .
			//             "    deklariert in %s\n" .
			//             "    Zeilen %d bis %d\n" .
			//             "    hat die Modifizierer %d [%s]\n",
			//                 $theClass->isInternal() ? 'internal' : 'user-defined',
			//                 $theClass->isAbstract() ? ' abstract' : '',
			//                 $theClass->isFinal() ? ' final' : '',
			//                 $theClass->isInterface() ? 'interface' : 'class',
			//                 $theClass->getName(),
			//                 var_export($theClass->getParentClass(), 1),
			//                 $theClass->getFileName(),
			//                 $theClass->getStartLine(),
			//                 $theClass->getEndline(),
			//                 $theClass->getModifiers(),
			//                 implode(' ', Reflection::getModifierNames($theClass->getModifiers()))
			//          );


			$cMethods =  $theClass->getMethods();

			#           $pane =& JPane::getInstance('sliders');
			#           echo $pane->startPane("the-pane");
			$indent = 0;
			$displayClassName = '';
			foreach ($cMethods as $cMethod)
			{
				$mPath = $cMethod->getFileName();

				//--$this class or $that class ;)
				//--..base or extended
				//..also marks the extended extended classes orange.. TODO !
				#$color =( $mPath == $fullPathFileName ) ? 'green' : 'orange';
				$titel = sprintf(
                  "%s%s%s%s%s%s Method <strong style='color: orange;'>%s</strong>",
				$cMethod->isAbstract() ? ' abstract' : '',
				$cMethod->isFinal()       ? ' final' : '',
				$cMethod->isPublic()      ? ' <strong style="color: green">public</strong>' : '',
				$cMethod->isPrivate()  ? ' <strong style="color: orange">private</strong>' : '',
				$cMethod->isProtected()   ? ' <strong style="color: red">protected</strong>' : '',
				$cMethod->isStatic()      ? ' <strong style="color: black">static</strong>' : '',
				$cMethod->getName()
				);
				$pClass= $cMethod->getDeclaringClass();
				$declaringClass = $pClass->getName();
				if( $declaringClass != $displayClassName )
				{

					$indent++;
					$html .= '<h1>';
					#  echo str_repeat("&nbsp;&nbsp;", $indent);
					$html .= ( $displayClassName ) ? '<span style="color: orange">Extends</span>&nbsp;'.$declaringClass : $declaringClass;
					$html .= '</h1>';
					$displayClassName = $declaringClass;
					$html .= NL.'<h2>Methods</h2>';

				}
				$paramString = array();
				$parameters = $cMethod->getParameters();
				$wikiParams = array();
				$wikiParamsDesc = '';
				foreach( $parameters as $parameter )
				{
					#$color =($parameter->isOptional() ) ? 'blue' : 'brown';
					$s = '';
					$s .= sprintf("%s<strong style='color: brown;'>$%s</strong>",
					#                     $parameter->isOptional() ? '<strong style="color: blue;">optional</strong> ' : '',
					$parameter->isPassedByReference() ? '<strong style="color: blue;"> & </strong>' : '',
					$parameter->getName()
					);

					//					$wikiParam = new JObject();
					//					$wikiParam->name = $parameter->getName();

					$wikiDefault = 'NODEFAULT';

					if( $parameter->isDefaultValueAvailable())
					{
						$def = $parameter->getDefaultValue();
						if( $def === null)
						{
							$s .= '=NULL';
							$wikiDefault = 'null';
						}
						else if( $def === false )
						{
							$s .= '=FALSE';
							$wikiDefault = 'false';
						}
						else if( $def === true )
						{
							$s .= '=TRUE';
							$wikiDefault = 'true';
						}
						else if( $def === array() )
						{
							$s .= '=array()';
							$wikiDefault = 'array()';
						}

						else if( $def === '' )
						{
							$s .= '=\'\'';
							$wikiDefault = "''";
						}
						else
						{
							$s .= '='.$parameter->getDefaultValue();
							$wikiDefault = $parameter->getDefaultValue();
						}
					}


				}//foreach
				$paramString = implode(', ', $paramString);

				if( strtolower($declaringClass) == strtolower($clas) )
				{
					$comment = explode(NL, $cMethod->getDocComment());
					$searches = array('@return', '@since');
					$syntaxAdds = '';
					$hasReturn = false;
					foreach ($comment as $c)
					{
						foreach ($searches as $search)
						{
							if( strpos($c, $search))
							{
								$c = str_replace($search, "'''".$search."'''", $c);
								$syntaxAdds .= trim($c).NL;
								if( $search == '@return'){ $hasReturn = true; }
							}
						}
					}//foreach

					//--Everythig starting with a '_' will be ignored - aka private..
					if( $cMethod->name == '_' || substr($cMethod->name, 0, 1) != '_')
					{

						$wikiMethodsPages[] = $wikiMethodsPage;
						$wikiClassPage .= '|-'.NL;
						$wikiClassPage .= '| [['.$wikiClassPrefix.'/'.$theClass->getName().'/'.$cMethod->name.'|'.$cMethod->name.']]'.NL;
						$wikiClassPage .= '|{{@todo|beschreibung}}'.NL;
					}
				}
				$comment = $cMethod->getDocComment();
				if( $comment )
				{
					$html .= NL.'<div style="border: 1px dotted grey; background-color: white;" class="doccomment_doccomment">';
					#  echo '<pre>';
					#  echo $comment;
					#$comment = str_replace("\n", '<br />', $comment);
					$html .= nl2br($comment);
					#echo $comment;
					#     echo '</pre>';
					$html .= '</div>';
				}
				$fileLocation = substr($cMethod->getFileName(), strlen(JPATH_SITE)).'<br />'.'Lines'.' # '.$cMethod->getStartLine().' - '.$cMethod->getEndLine();
				//             echo NL.'<span class="doccomment_sourcecode hasTip" title="'.$fileLocation.'">';
				//             echo NL.'<a class="modal" rel="{handler: \'iframe\', size: {x: 950, y: 550}, effects:Fx.Transitions.Bounce.easeOut}"    href="'.$link.'">';
				//             echo 'Source code';
				//             echo NL.'</a></span>';

				#        print_r($parameters);
				#              echo var_export($cMethod->getDocComment(), 1);
				#        echo '<br />';
				#     echo NL.'<pre>';
				// Grundlegende Informationen ausgeben

				// Dokumentarischen Kommentar ausgeben
				#              printf("---> Dokumentation:\n %s\n", var_export($cMethod->getDocComment(), 1));

				// Statische Variablen ausgeben, falls welche existieren
				if ($statics = $cMethod->getStaticVariables()) {
					#                  $html .= '<pre>'.sprintf("---> Statische Variablen: %s\n", var_export($statics, 1)).'</pre>';
				}
			}//foreach

		}//foreach

		if( ! JLoader::import('helpers.format.'.$output_format, JPATH_COMPONENT))
		{
			echo 'unknown format';

			return false;
		}
		$className = 'ReflectorFormat';//.$output_format;
		if( ! class_exists($className))
		{
			printf('Required class %s not found', $className);

			return false;
		}
		
		return ReflectorFormat::reflect($rawObject);
	}//function

}//class